package cz.cuni.amis.episodic.bayes.memories;

import java.util.Collection;
import java.util.List;

import lombok.Getter;

import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;

import cz.cuni.amis.episodic.bayes.utils.MemChart;
import cz.cuni.amis.episodic.bayes.utils.NodeSnapshot;
import cz.cuni.amis.episodic.bayes.utils.Utils;
import cz.cuni.amis.episodic.bayes.utils.chart.GraphPaintingDevice;
import cz.cuni.amis.episodic.dybanem.DBN;
import cz.cuni.amis.episodic.dybanem.Evidence;

/**
 * 
 * @author ik
 */
public abstract class KLBasedMemoryCreator implements MemoryCreator {

	public KLBasedMemoryCreator(GraphPaintingDevice graphPaintingDevice,
			String graphName) {
		this.graphPaintingDevice = graphPaintingDevice;
		this.strategyName = graphName;
	}

	public KLBasedMemoryCreator(GraphPaintingDevice graphPaintingDevice) {
		this.graphPaintingDevice = graphPaintingDevice;
	}

	GraphPaintingDevice graphPaintingDevice;

	@Getter
	String strategyName = "retrospective";

	NodeSnapshot[] currentSnapshots; 
	
	protected abstract MemoryElement createMemoryInternal(String[] targets,
			NodeSnapshot[] trueSnapshots, DBN dbn,
			Collection<? extends Evidence> evidences, int iteration);
	
	@Override
	public MemoryElement createMemory(String[] targets,
			NodeSnapshot[] trueSnapshots, DBN dbn,
			Collection<? extends Evidence> evidences, int iteration) {
		
		
        
        // create snapshot given current memory
        currentSnapshots = dbn.getNodesSnapshot(targets);
        // draw prior probability graph 
        drawPriorProbabilityGraphs(currentSnapshots, dbn, iteration);
        
        long start = System.nanoTime();
        MemoryElement mem = createMemoryInternal(targets, trueSnapshots, dbn, evidences, iteration);
        
        long elapsedNanos = System.nanoTime() - start;
        mem.setTimeNanoToCompute(elapsedNanos);
        
        return mem;
	}
	
	
	double initialMaximumKL = 0;
	
	void drawKLGraph(double[][] kl, String[] targets, int iteration) {
		if(iteration == 0) {
			initialMaximumKL = Utils.max(kl);
		}
		
		if (graphPaintingDevice != null) {
			try {
				graphPaintingDevice.outputGraph(MemChart.chartXYBlockValueTime(
						kl, targets, 0, initialMaximumKL, "Memory creation KL"), strategyName,
						iteration);
			} catch (Exception ex) {
				throw new RuntimeException(ex);
			}

		}
	}

	/**
	 * Draws graphs that show probability prior to creating the mem.
	 * 
	 * @param nodesSnapshots
	 *            list of nodes usually in one time slice
	 */
	 public void drawPriorProbabilityGraphs(NodeSnapshot[] nodesSnapshots, DBN net,
			int iteration) {
		drawPriorProbabilityGraphs(nodesSnapshots, net, iteration, graphPaintingDevice, strategyName);
	}

	 public static void drawPriorProbabilityGraphs(NodeSnapshot[] nodesSnapshots, DBN net,
				int iteration, GraphPaintingDevice graphPaintingDevice, String strategyName) {
			if (graphPaintingDevice != null) {
				for (NodeSnapshot snapshot : nodesSnapshots) {
					try {
						graphPaintingDevice.outputGraph(MemChart
								.chartXYBlockTimeValue(
										snapshot.getProbability(),
										net.getNet().getOutcomeIds(
												snapshot.getNode())), strategyName
								+ "_" + snapshot.getNode() + "_prior", iteration);
					} catch (Exception e) {
						throw new RuntimeException(e);
					}
				}
			}
		}

}
